package com.futvan.z.framework.core;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;

import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.mybatis.spring.SqlSessionTemplate;
import org.quartz.Scheduler;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;

import com.futvan.z.system.zaccesskey.z_accesskey;
import com.futvan.z.system.zaccesskey.z_accesskey_ip;
import com.futvan.z.system.zcode.z_code;
import com.futvan.z.system.zcode.z_code_detail;
import com.futvan.z.system.zdb.z_db;
import com.futvan.z.system.zdb.z_db_table;
import com.futvan.z.system.zdb.z_db_table_column;
import com.futvan.z.system.zetlin.z_etl_in;
import com.futvan.z.system.zhttpservices.z_http_services;
import com.futvan.z.system.zjob.z_job;
import com.futvan.z.erp.cms_column.cms_column;
import com.futvan.z.erp.cms_info.cms_info;
import com.futvan.z.erp.erp_account_type.erp_account_type;
import com.futvan.z.framework.common.bean.Code;
import com.futvan.z.framework.common.bean.Result;
import com.futvan.z.system.zform.z_form;
import com.futvan.z.system.zform.z_form_table;
import com.futvan.z.system.zform.z_form_table_button;
import com.futvan.z.system.zform.z_form_table_column;
import com.futvan.z.system.zorg.z_org;
import com.futvan.z.system.zreport.z_report;
import com.futvan.z.system.zreport.z_report_column;
import com.futvan.z.system.zuser.z_user;
import com.futvan.z.system.zworkflow.z_workflow;
import com.futvan.z.framework.util.DateUtil;
import com.futvan.z.framework.util.JobUtil;
import com.futvan.z.framework.util.MathUtil;
import com.futvan.z.framework.util.SpringUtil;
import com.futvan.z.framework.util.StringUtil;
import com.futvan.z.framework.util.SystemUtil;
import com.futvan.z.system.zmessages.z_messages;
@Component
public class z extends SuperZ implements InitializingBean{
	private static Logger logger = Logger.getLogger(z.class);
	//所有其它库
	public static Map<String,SqlSessionTemplate> dbs;//所有其它数据库
	public static Map<String,z_db> dbsMap;//所有其它数据库 key=dbid
	public static Map<String,z_db_table> dbTableMap;//所有其它数据库 key=tableid
	public static Map<String,z_db_table_column> dbTableColumnMap;//所有其它数据库 key=tableid_columnid
	public static Map<String,z_form> forms;//所有forms
	public static Map<String,z_form> form_tableid;//所有forms信息key=Table_id
	public static Map<String,z_form_table> tables;//系统所有表信息
	public static Map<String,z_form_table> tablesForZid;//系统所有表信息
	public static Map<String, z_form_table_column> columns;//key=Table_id+"_"+Column_id
	public static Map<String, z_form_table_column> columnsForColumnZid;//key=ColumnZid 所有字段，根据字段ZID查找
	public static Map<String, z_form_table_button> buttons;//所有表按钮key=Table_id+"_"+button_id
	public static Map<String, z_form_table_button> buttonsForZid;//所有表按钮key=buttonzid
	public static Map<String,z_report> reports;//系统所有报表信息 key=zid
	public static Map<String,z_report_column> reportColumns;//系统所有报表字段信息 key=reportid_column_id
	public static Map<String,String> formidToProjects;//Form关联的项目ID  key=z_form.form_id value= z_project.project_id
	public static Map<String,String> formzidToProjects;//Form关联的项目ID  key=z_form.zid value= z_project.project_id
	public static Map<String,z_workflow> wf;//工作流模板对象
	public static Map<String,List<z_workflow>> wfListForTableid;//工作流模板对象,根据TableID
	public static Map<String,z_code> code;//所有Code信息 
	public static Map<String,z_code_detail> code_detail;//所有code_detail信息  {codeid}_{z_key}
	public static Map<String,String> codeValue;//所有Code内容信息 
	public static Map<String,String> Z5DisplayValue;//Z5字段显示值
	public static Map<String,String> sp;//系统参数system parameter 
	public static Map<String,z_accesskey> accesskey;//接口密钥 根据Accesskeyid查询，返回z_accesskey对象
	public static Map<String,z_http_services> httpservices;//http接口 根据接口serviceid查询 ，返回z_http_services
	public static Map<String,z_http_services> httpservices_zid;//http接口 根据接口zid查询 ，返回z_http_services
	public static Map<String,z_org> orgs;//系统所有组织
	public static Map<String,List<String>> lowerOrgids;//所有下级组织ID
	public static Map<String,List<String>> lowerOrgUsers;//所有下级组织用户ID
	public static Map<String,String> UserFunctionButtons;//用户表单功能按钮权限 userid+buttonId
	public static Map<String,String> UserReportButtons;//用户报表功能按钮权限 userid+buttonId
	public static Map<String,z_user> users;//系统所有用户
	public static Map<String,z_user> users_tel;//系统所有用户
	public static Map<String,z_user> users_userid;//系统所有用户
	public static Map<String,z_user> users_idcard;//系统所有用户
	public static Map<String,WebSocketSession> socket_session_users;//Socket通信中所有用户信息key:user_zid value:WebSocketSession
	public static Map<String,z_user> session_users;//所有Session中的用户
	public static Map<String,erp_account_type> account_type;//所有账户类型
	public static Scheduler job;//任务工厂
	public static Map<String,z_etl_in> etls;//所有数据抽取记录
	public static Map<String,HashMap<String,String>> jobRunList;//当前运行的任务
	public static Map<String,cms_info> cms;//所有资讯key:zid
	public static Map<String,cms_info> cmsForNumber;//所有资讯key:number
	public static Map<String,cms_column> cmsColumn;//所有资讯栏目key:zid
	public static List<cms_column> cmsColumn0List;//所有1级栏目
	public static Map<String,List<cms_column>> cmsColumnDetail;//所有资讯栏目子栏目
	public static Map<String,cms_column> cmsColumnForNumber;//所有资讯栏目key:number
	public static Map<String,List<cms_info>> cmsList;//指定栏目下所有资讯记录key:栏目zid


	public void afterPropertiesSet() throws Exception {
		socket_session_users = new HashMap<String,WebSocketSession>();
		session_users = new HashMap<String, z_user>();

		//加载系统参数
		RLoadParameter();

		//初始化系统任务
		initJob();

		//删除Fomr表中垃圾数据
		deleteFormGarbage();
	}


	/**
	 * 启用系统定时任务
	 * @throws Exception 
	 */
	private void initJob() throws Exception {
		jobRunList = new HashMap<String, HashMap<String,String>>();
		//判读当前系统是否启用系统任务模块
		if("true".equals(sp.get("is_start_job"))) {
			//启动任务工厂
			job = StdSchedulerFactory.getDefaultScheduler();
			job.start();

			//添加系统任务
			String sql = "SELECT * FROM z_job WHERE isstart = 1";
			z_job parameter = new z_job();
			parameter.setIsstart("1");
			List<z_job> jobList = sqlSession.selectList("z_job_select", parameter);
			for (z_job job : jobList) {
				JobUtil.jobAdd(job);
			}
			z.Log("计划任务启动：成功");
		}
	}

	/**
	 * 手动获取sqlSession
	 * @return
	 */
	public static SqlSession getSqlSession() {
		Object obj = SpringUtil.getBean("sqlSession");
		if(z.isNotNull(obj) && obj instanceof SqlSession) {
			return (SqlSession)obj;
		}else {
			return null;
		}
	}

	/**
	 * 发送消息
	 * @param userid
	 * @param msg
	 * @return
	 */
	public static Result sendMessage(String userid,String msg) {
		return WebSocketHandler.sendMessage(userid,msg);
	}

	public static void Log(Object log) {
		logger.warn(log);
	}

	public static void Error(Object log){
		Error(log,null);
	}

	public static void Error(Object log,Exception e){
		StringBuffer errorinfo = new StringBuffer();
		errorinfo.append(log).append("\r\n");
		if(z.isNotNull(e)) {
			errorinfo.append(StringUtil.ExceptionToString(e)).append("\r\n");
		}

		//如果启动即时通讯，出现异常信息发送到前台显示
		if(z.isNotNull(z.sp) && "true".equals(z.sp.get("isMSN"))) {
			try {
				//发送异常信息给前台
				z_messages msg = new z_messages();
				msg.setTouserid(getUserId());//接收人
				msg.setMsg(errorinfo.toString());//异常信息
				msg.setCommand_type("e_message");//信息类型
				//发送信息
				WebSocketHandler.sendMessage(msg);
				logger.warn(errorinfo);
			} catch (java.lang.Exception e1) {
				//发果通过webSocket发送异常信息出错，直接发送到控制台
				logger.warn(errorinfo);
			}
		}else{
			logger.warn(errorinfo);
			System.out.println(errorinfo);
		}

	}

	/**
	 * 是否不为空
	 * @return
	 */
	public static boolean isNotNull(Object obj) {
		if(obj!=null && !"".equals(obj) && !"null".equals(obj) && !"NULL".equals(obj) && !"Null".equals(obj) && !"NuLL".equals(obj)) {
			return true;
		}else {
			return false;
		}
	}

	/**
	 * 是否为空
	 * @return
	 */
	public static boolean isNull(Object obj) {
		if(obj==null || "".equals(obj) || "null".equals(obj) || "NULL".equals(obj) || "Null".equals(obj) || "NuLL".equals(obj)) {
			return true;
		}else {
			return false;
		}
	}

	/**
	 * 	创建ZID
	 * @param tableId 表ID
	 * @return
	 */
	public static String newZid(String tableId) {
		String uuid = UUID.randomUUID().toString().replace("-", "");
		if(!"".equals(tableId) && tableId!=null) {
			uuid = uuid+"☆"+tableId;
			uuid = StringUtil.jia(uuid);
		}
		return uuid;
	}

	/**
	 * 创建编号
	 * @param TableName 表名
	 * @return
	 */
	public static String newNumber(){
		return newNumber("","yyyyMMddHHmmssSSS",6);
	}

	/**
	 * 创建6位短信验证码
	 * @return
	 */
	public static String newZcode(){
		return newNumber("","",6);
	}

	/**
	 * 创建编号
	 * @param head 标识
	 * @param pattern 时间格式
	 * @param digit 随机长度
	 * @return
	 */
	public static String newNumber(String head,String pattern,int digit){
		StringBuffer returnvalue = new StringBuffer();

		//生成头标示
		if(!"".equals(head) && head!=null){
			returnvalue.append(head);
		}
		//生成日期标示
		if(z.isNotNull(pattern)) {
			String dateInfo = DateUtil.FormatDate(new java.util.Date(),pattern);
			returnvalue.append(dateInfo);
		}

		//生成随机数标示
		Random random = new Random();
		String fd = "";
		for (int i = 0; i < digit; i++) {
			fd = fd + "0";
		}
		returnvalue.append(MathUtil.FormatNumber((random.nextInt(new BigDecimal("1"+fd).intValue())%(new BigDecimal("1"+fd).intValue()-1+1) + 1),fd));

		return returnvalue.toString();
	}

	/**
	 * 抛出异常
	 * @param e
	 * @throws Exception
	 */
	public static void Exception(String e) throws Exception {
		throw new Exception(e);
	}

	/**
	 * 验证接口权限
	 * @param bean
	 * @return
	 */
	public static Result isServiceAuthority(HashMap<String, String> bean,HttpServletRequest request) {
		Result result = new Result();
		if(z.isNotNull(bean.get("is_oa_call"))) {
			//如果是系统OA流程调用，不验证权限
			result.setCode(Code.SUCCESS);
		}else {
			String methodName = request.getServletPath();
			if(z.isNotNull(methodName) && methodName.length()>1) {
				methodName = methodName.substring(1);
				z_http_services s = z.httpservices.get(methodName);
				if(z.isNotNull(s)) {
					if("1".equals(s.getIsenable())) {//是否启用
						String accesskeyid = bean.get("accesskeyid");
						if(z.isNotNull(accesskeyid)) {
							String accesskeysecret = bean.get("accesskeysecret");
							if(z.isNotNull(accesskeysecret)) {
								//判断接口密钥是否正确
								z_accesskey db_accesskey = z.accesskey.get(accesskeyid);
								if(z.isNotNull(db_accesskey)) {
									String db_accesskeysecret = db_accesskey.getAccesskeysecret();
									if(db_accesskeysecret.equals(accesskeysecret)) {
										//判读接口密钥是否启用IP验证
										if(z.isNotNull(db_accesskey.getZ_accesskey_ip_list()) 
												&& db_accesskey.getZ_accesskey_ip_list().size()>0) {
											String customIp = request.getRemoteAddr();//访问者IP
											List<z_accesskey_ip> iplist = db_accesskey.getZ_accesskey_ip_list();
											boolean isOK = false;
											for (z_accesskey_ip ip : iplist) {
												if(customIp.equals(ip.getIp())) {
													isOK = true;
												}
											}
											if(isOK) {//如果通过IP验证，运行接口
												result.setCode(Code.SUCCESS);
											}else {
												result.setCode(Code.ERROR);
												result.setMsg("非法IP访问接口："+customIp);
											}
										}else {
											//未启用IP验证,运行接口
											result.setCode(Code.SUCCESS);
										}
									}else {
										result.setCode(Code.ERROR);
										result.setMsg("密钥密码错误："+accesskeysecret);
									}
								}else {
									result.setCode(Code.ERROR);
									result.setMsg("非法接口密钥："+accesskeyid);
								}
							}else {
								result.setCode(Code.ERROR);
								result.setMsg("accesskeysecret：不能为空");
							}
						}else {
							result.setCode(Code.ERROR);
							result.setMsg("accesskeyid：不能为空");
						}

					}else {
						result.setCode(Code.ERROR);
						result.setMsg("接口未启用|"+methodName);
					}
				}else {
					result.setCode(Code.ERROR);
					result.setMsg("无效接口标识|"+methodName);
				}
			}else {
				result.setCode(Code.ERROR);
				result.setMsg("无效接口标识|"+methodName);
			}



		}
		return result;
	}

}
